﻿#include "BlockListener.h"
#include "global.h"

////进入作用域
void BlockListener::enterBlock(PinParser::BlockContext* ctx)
{

    //std::cout << u8"作用域开始" << std::endl;

    ++isInBlock;
}

//退出作用域
void BlockListener::exitBlock(PinParser::BlockContext* ctx)
{
	//std::cout << u8"作用域结束";

    --isInBlock;
}

 void BlockListener::enterProgram(PinParser::ProgramContext* ctx)
{
/*
    if(ctx->defglobal() != nullptr)
    {
        enterDefglobal(ctx->defglobal());
    }

     std::vector<PinParser::FunctionContext*> vec = ctx->function();

	 for (int i = 0; i < vec.size(); ++i)
	 {
		 enterFunction(vec.at(i));
     }
*/
}

void BlockListener::exitDefglobal(PinParser::DefglobalContext* /*ctx*/)
 {
    --isInBlock;
 }

void BlockListener::enterDefglobal(PinParser::DefglobalContext * ctx)
{
    ++isInBlock;

    if(gloablTimes > 0)
    {
        QString err = QString(u8"错误：行号：%1 有多个global 或 quanju_dingyi ，不能定义多个全区作用域！").arg(curLine);
        AbortException(err);
    }
    ++gloablTimes;

    std::vector<std::string> empty;

    //antlr4::Token* startToken = ctx->getStart();
    //antlr4::Token* stopToken = ctx->getStop();

    //这样获取的函数体，已经是包含注释的了。因为注释目前没有删除，而是去到隐藏通道。
    //std::string block = tokens->getText(antlr4::misc::Interval(startToken->getTokenIndex(), stopToken->getTokenIndex()));
    std::string block;
    FUN_SYM_INFO* pSym = addFunBlock(ctx->GLOBAL()->getText(), block, empty,empty);
    pSym->funNameLineNum = ctx->getStart()->getLine();
    pSym->pBlock = ctx;

}


void BlockListener::errorValidState(antlr4::ParserRuleContext* ctx)
{
    if (isInBlock == 0)
    {
        std::cout << ctx->getText() << std::endl;
        int startIndex = ctx->getStart()->getTokenIndex();
        int stopIndex = startIndex;



        std::string errorLineText;

        int line = curLine;

        tokens->fill();

        int lineStart = ctx->getStart()->getLine();
        int lienEnd = ctx->getStop()->getLine();

        while (startIndex >= 0 && startIndex < tokens->size() && (tokens->get(startIndex)->getLine() == line)) {
            --startIndex;
        }
        ++startIndex;

        while (stopIndex < tokens->size() && (tokens->get(stopIndex)->getLine() < (line + 1))) {
            ++stopIndex;
        }
        stopIndex--;

        // 获取出错行的文本
        if (startIndex >= 0 && startIndex <= stopIndex)
        {
            errorLineText = tokens->getText(antlr4::misc::Interval((size_t)startIndex, (size_t)stopIndex));
        }
        QString et = QString::fromStdString(errorLineText);
        et = et.trimmed();

        QString msg = QString(u8"错误：行号 %1 字段 %2 语句 %3 不是合法的语句，请检查拼写错误！有不能识别的错误词，或存在不受作用域约束的随意语句!\n所有语句只能出现在函数块或全局定义quanju_dinyi 块中，不能随处写！").arg(curLine).arg(curStatement).arg(et);
        AbortException(msg);
    }
}

////必须在作用域内
void BlockListener::enterStatement(PinParser::StatementContext* ctx)
{
    errorValidState(ctx);
}

void BlockListener::enterDeclareStruct(PinParser::DeclareStructContext *ctx)
{
    errorValidState(ctx);
}

//void BlockListener::enterUnknown(PinParser::UnknownContext * ctx)
//{
//    std::cout << ctx->getText() << std::endl;
//    int startIndex = ctx->getStart()->getTokenIndex();
//    int stopIndex = startIndex;
//
//    
//
//    std::string errorLineText;
//
//    int line = curLine;
//
//    tokens->fill();
//
//    int lineStart = ctx->getStart()->getLine();
//    int lienEnd = ctx->getStop()->getLine();
//
//    while (startIndex >=0 && startIndex < tokens->size() && (tokens->get(startIndex)->getLine() == line)) {
//        --startIndex;
//    }
//    ++startIndex;
//
//    while (stopIndex < tokens->size() && (tokens->get(stopIndex)->getLine() < (line+1))) {
//        ++stopIndex;
//    }
//    stopIndex--;
//
//    // 获取出错行的文本
//    if (startIndex >= 0 && startIndex <= stopIndex)
//    {
//        errorLineText = tokens->getText(antlr4::misc::Interval((size_t)startIndex, (size_t)stopIndex));
//    }
//    QString et = QString::fromStdString(errorLineText);
//    et = et.trimmed();
//
//    QString msg = QString(u8"错误：行号 %1 字段 %2 语句 %3 不是合法的语句，请检查拼写错误！有不能识别的错误词，或存在不受作用域约束的随意语句!\n所有语句只能出现在函数块或全局定义quanju_dinyi 块中，不能随处写！").arg(curLine).arg(curStatement).arg(et);
//
//
//    AbortException(msg);
//
//}
//

//进入函数定义
void BlockListener::enterFunction(PinParser::FunctionContext* ctx)
{
    ++isInBlock;

    if (ctx->VARNAME() != nullptr)
	{
		//获取函数名称
        std::string funName = ctx->VARNAME()->getText();

        int lineNum = ctx->getStart()->getLine();

#ifdef PIN_DEBUG
        std::cout << u8"发现函数： " << funName << u8" 行号 " << lineNum << std::endl;
#endif

        FUN_SYM_INFO* pExistFun = findFunBlock(funName);
        if(pExistFun != nullptr)
        {
            QString msg = QString(u8"错误：行号 %1 函数 %2 重复定义，行 %3 已经存在一个同名函数 %1").arg(lineNum).arg(QStr(funName)).arg(pExistFun->funNameLineNum);
            AbortException(msg);
            return;
        }

        //std::cout << "--3 block " <<  ctx->getText() << std::endl;
		PinParser::BlockContext* blockCtx = ctx->block();

		if (blockCtx != nullptr)
		{
    //不需要函数体了，后面不是翻译执行，而是直接语法树执行。
#if 0
            //block->gettext()没有包含注释行。而这样获得的才有。因为现在隐藏通道有所有注释。
            // 获取函数块的起始和结束令牌
            antlr4::Token* startToken = blockCtx->getStart();
            antlr4::Token* stopToken = blockCtx->getStop();

            //这样获取的函数体，已经是包含注释的了。因为注释目前没有删除，而是去到隐藏通道。
            std::string block = tokens->getText(antlr4::misc::Interval(startToken->getTokenIndex(), stopToken->getTokenIndex()));;
#endif

            std::vector<std::string> paraList;
            std::vector<std::string> retList;

#ifdef PIN_DEBUG
			//如果有参数
			std::string paras;
            std::string retargs;
#endif

			PinParser::DefArgumentListContext* pArgs = ctx->defArgumentList();
			if (pArgs != nullptr)
			{
				std::vector<PinParser::DefArgumentContext*> argVec = pArgs->defArgument();

                //先加入变量名称
                for (int i = 0, c = argVec.size(); i < c; ++i)
                {
                    if(argVec.at(i)->VARNAME().size() == 1)
                    {
                        paraList.push_back(argVec.at(i)->VARNAME(0)->getText());
                    }
                    else if(argVec.at(i)->VARNAME().size() == 2) //结构体
                    {
                        paraList.push_back(argVec.at(i)->VARNAME(1)->getText());
                    }
                }

                //再加入变量类型
				for (int i = 0, c = argVec.size(); i < c; ++i)
				{

                    if(argVec.at(i)->TYPE_ID() != nullptr)
                    {
                        paraList.push_back(argVec.at(i)->TYPE_ID()->getText());
#ifdef PIN_DEBUG
                        paras += argVec.at(i)->getText() + " ";
#endif
                    }

                    else if(argVec.at(i)->HUIDIAO() != nullptr) //函数做参数
                    {
                        //函数的参数检查的时候，和变量一样，只需要函数形参即可。这里其实是回调函数。类似暂时做hd处理。
                        paraList.push_back("hs");

#ifdef PIN_DEBUG
                        paras += argVec.at(i)->getText() + " ";
#endif
                    }
                    else if(argVec.at(i)->VARNAME().size() == 2) //结构体
                    {
                        //结构体的参数检查的时候，输入结构体.对象名称的方式。对象名称需要，后面参数入栈的时候需要。
                        paraList.push_back(argVec.at(i)->VARNAME(0)->getText());

#ifdef PIN_DEBUG
                        paras += argVec.at(i)->VARNAME(0)->getText();
#endif
                    }
                    else
                    {
                        QString msg = QString(u8"错误：函数 %1 非法的参数类型").arg(QStr(funName));
                        AbortException(msg);
                    }



				}
			}

            PinParser::DefFunRetContext* pRets = ctx->defFunRet();
            if(pRets != nullptr)
            {
                std::vector<PinParser::FunretArgContext *> retVec = pRets->funretArg();

                //std::vector<PinParser::PinvarContext *> retVec = pRets->pinvar();

                for (int i = 0, c = retVec.size(); i < c; ++i)
                {
                    if(retVec.at(i)->TYPE_ID() != nullptr)
                    {
                        retList.push_back(retVec.at(i)->TYPE_ID()->getText());
#ifdef PIN_DEBUG
                        retargs += retVec.at(i)->getText() + " ";
#endif
                    }
                    else if(retVec.at(i)->VARNAME() != nullptr)
                    {
                        //结构体的参数检查的时候，只需要结构体的类名称即可，不需要后面具体的对象名称
                        retList.push_back(retVec.at(i)->VARNAME()->getText());
#ifdef PIN_DEBUG
                        retargs += retVec.at(i)->VARNAME()->getText() + " ";
#endif
                    }
                }
            }
#ifdef PIN_DEBUG
            std::cout << u8"函数参数" << paras << std::endl;
            std::cout << u8"函数返回值" << retargs << std::endl;
            //std::cout << u8"函数体：" << block << std::endl;
    #endif
            std::string block;
            FUN_SYM_INFO* pNewSym = addFunBlock(funName, block, paraList,retList);
            pNewSym->funNameLineNum = lineNum;
            pNewSym->blockLineNum = blockCtx->getStart()->getLine();
            pNewSym->pBlock = blockCtx;

            // 获取不包含 block 的部分
            ssize_t startIndex = ctx->getStart()->getTokenIndex();
            ssize_t stopIndex = ctx->block()->getStart()->getTokenIndex() - 1;


            QByteArray desc = QByteArray::fromStdString(tokens->getText(antlr4::misc::Interval(startIndex, stopIndex)));
            desc = desc.trimmed();

            //去掉hanshu 
            desc = desc.mid(6);

            //去掉前后的空白
            pNewSym->funDec = desc.toStdString();

            //20250202 把函数名称也做全局变量的一种

            SymNode* pfunSym = new SymNode;
#ifdef PIN_MEM_REF
            newTime();
#endif
            pfunSym->type = EXPR_FUN;
            pfunSym->name = funName;
            pfunSym->value.vpoint = new std::string(funName);
#ifdef PIN_MEM_REF
            newTime();
#endif
            insertGlobalSymTable(funName, pfunSym);

		}

	}


}

//退出函数
void BlockListener::exitFunction(PinParser::FunctionContext* ctx)
{
    --isInBlock;
}
